package com.minimalist.basic.config.fileHandler.handler.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.minimalist.basic.config.exception.BusinessException;
import com.minimalist.basic.config.fileHandler.FileManager;
import com.minimalist.basic.config.fileHandler.entity.MinIOFileEntity;
import com.minimalist.basic.config.fileHandler.handler.FileHandler;
import com.minimalist.basic.entity.enums.FileEnum;
import com.minimalist.basic.entity.enums.StatusEnum;
import com.minimalist.basic.entity.enums.StorageEnum;
import com.minimalist.basic.entity.po.MFile;
import com.minimalist.basic.entity.po.MStorage;
import com.minimalist.basic.mapper.MStorageMapper;
import com.minimalist.basic.utils.UnqIdUtil;
import com.minimalist.basic.utils.ValidateUtil;
import com.mybatisflex.core.query.QueryWrapper;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
/**
 * @author 11987
 */

@Slf4j
@Service
public class MinIOFileHandler implements FileHandler {

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    private FileManager fileManager;

    @Autowired
    private MStorageMapper mStorageMapper;

    /**
     * 是否是对应的处理类
     * @param storageType 存储类型
     * @return 处理类
     */
    @Override
    public boolean isHandler(String storageType) {
        return StorageEnum.StorageType.MINIO.getCode().equals(storageType);
    }

    /**
     * 参数校验
     * @param storageConfig JSON存储配置信息
     */
    @Override
    public String valid(String storageConfig) {
        MinIOFileEntity minIOFileEntity = JSONUtil.toBean(storageConfig, MinIOFileEntity.class);
        ValidateUtil.valid(minIOFileEntity);
        return storageConfig;
    }

    /**
     * 单文件上传
     * @param multipartFile 文件
     * @param fileSource 文件来源
     * @param storage 存储信息
     * @return 文件信息
     */
    @Override
    public MFile uploadFile(MultipartFile multipartFile, Integer fileSource, MStorage storage) {
        try {
            // 根据文件来源，获取相对路径
            String fileSourcePath = fileManager.getPathByFileSource(fileSource);
            // MinIO 存储配置
            MinIOFileEntity minioConfig = JSONUtil.toBean(storage.getStorageConfig()
                    , MinIOFileEntity.class);
            String endpoint = minioConfig.getEndPoint();
            String accessKey = minioConfig.getAccessKey();
            String secretKey = minioConfig.getSecretKey();
            String bucketName = minioConfig.getBucketName();
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint(endpoint)
                            .credentials(accessKey, secretKey)
                            .build();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder()
                            .bucket(bucketName).build());
            if (!isExist) {
                minioClient.makeBucket(MakeBucketArgs.builder()
                        .bucket(bucketName).build());
            }
            String fileSuffix = FileNameUtil.extName(multipartFile.getOriginalFilename());
            String newFileName = IdUtil.objectId() + "." + fileSuffix;
            String url = endpoint + "/" + bucketName + "/";
            MFile fileInfo = new MFile();
            fileInfo.setFileId(UnqIdUtil.uniqueId());
            fileInfo.setFileName(multipartFile.getOriginalFilename());
            fileInfo.setNewFileName(newFileName);
            fileInfo.setFileSize(multipartFile.getSize());
            fileInfo.setFileType(multipartFile.getContentType());
            fileInfo.setFileBasePath(bucketName);
            fileInfo.setFilePath(fileSourcePath);
            fileInfo.setFileUrl(url + fileSourcePath);
            fileInfo.setFileSource(fileSource);
            fileInfo.setStorageType(storage.getStorageType());
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileSourcePath)
                            .stream(multipartFile.getInputStream()
                                    , multipartFile.getSize(), -1)
                            .contentType(multipartFile.getContentType())
                            .build());
            if (StrUtil.isNotBlank(multipartFile.getContentType())
                    && multipartFile.getContentType().contains("image")) {
                String thFileName = "thumbnail-" + newFileName;
                String thPath = fileSourcePath + thFileName;
                File thFile = FileUtil.touch(thPath);
                Thumbnails.of(multipartFile.getInputStream())
                        .scale(0.4)
                        .toFile(thFile);
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(bucketName)
                                .object(thPath)
                                .stream(new FileInputStream(thFile)
                                        , thFile.length(), -1)
                                .contentType(multipartFile.getContentType())
                                .build());
                fileInfo.setFileThUrl(url + thPath);
                fileInfo.setFileThFilename(thFileName);
                fileInfo.setFileThSize(thFile.length());
            }
            return fileInfo;
        } catch (Exception e) {
            log.warn("上传文件，异常：", e);
            throw new BusinessException(FileEnum.ErrorMsg
                    .FILE_UPLOAD_FAIL.getDesc());
        }
    }

    /**
     * 删除文件
     * @param file 文件信息
     * @return 是否删除成功
     */
    @Override
    public boolean deleteFile(MFile file) {
        try {
            QueryWrapper queryWrapper = QueryWrapper.create()
                    .select()
                    .from(MStorage.class)
                    .where(MStorage::getStorageType)
                    .eq(StorageEnum.StorageType.MINIO.getCode())
                    .and(MStorage::getStatus)
                    .eq(StatusEnum.STATUS_1.getCode());
            MStorage mStorage = mStorageMapper.selectOneByQuery(queryWrapper);
            if (mStorage == null) {
                log.warn("minio存储配置不存在，无法删除文件");
                return false;
            }
            MinIOFileEntity minioConfig = JSONUtil.toBean(mStorage.getStorageConfig()
                    , MinIOFileEntity.class);
            String endpoint = minioConfig.getEndPoint();
            String accessKey = minioConfig.getAccessKey();
            String secretKey = minioConfig.getSecretKey();
            String bucketName = minioConfig.getBucketName();
            try (MinioClient minioClient = MinioClient.builder()
                    .endpoint(endpoint).credentials(accessKey, secretKey).build()) {
                String filePath = file.getFilePath();
                log.info("删除文件，路径：{}", filePath);
                minioClient.removeObject(RemoveObjectArgs.builder()
                        .bucket(bucketName).object(filePath).build());
                if (StrUtil.isNotBlank(file.getFileThFilename())) {
                    String fileThPath = file.getFilePath() + file.getFileThFilename();
                    log.info("删除缩略图，路径：{}", fileThPath);
                    minioClient.removeObject(
                            RemoveObjectArgs.builder()
                                    .bucket(bucketName)
                                    .object(fileThPath)
                                    .build());
                }
            }
            return true;
        } catch (Exception e) {
            log.warn("删除文件，异常：", e);
            return false;
        }
    }
}
